package com.nhncorp.mojo.jumble;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.InvalidDependencyVersionException;
import org.apache.maven.project.artifact.MavenMetadataSource;
import org.apache.maven.settings.Server;
import org.codehaus.plexus.archiver.jar.JarArchiver;

/**
 * 
 * @author NHN Corporation
 * @version $Rev$, $Date$
 */
public abstract class AbstractJumbleMojo extends AbstractMojo {
	/**
	 * The Maven project instance for the executing project.
	 * <p>
	 * Note: This is passed by Maven and must not be configured by the user.
	 * </p>
	 * 
	 * @parameter expression="${project}"
	 * @readonly
	 * @required
	 */
	protected MavenProject project;

	/**
	 * Debug mode
	 * 
	 * @parameter expression="${ntaf.debug}" default-value="false"
	 */
	protected boolean debug;

	/**
	 * Replace Fitnesse classpath
	 * 
	 * @parameter default-value="true"
	 */
	protected boolean replaceContent;

	/**
	 * Execute Fitnesse server
	 * 
	 * @parameter default-value=""
	 */
	protected String jumbleHome;
	
	/**
	 * Execute Fitnesse server
	 * 
	 * @parameter default-value=""
	 */
	protected String xmlOutput;

	/**
	 * Execute Fitnesse server
	 * 
	 * @parameter default-value=""
	 */
	protected String mutator;

	
	/**
	 * Java Command Executable
	 * 
	 * @parameter default-value="java"
	 */
	protected String jvm;

	/**
	 * JVM Option
	 * 
	 * @parameter default-value=""
	 */
	protected String argLine;

	/**
	 * This is the list of FitNesse server pages.<br/>
	 * A FitNesse tag is compose of the nested tags:<BR/>
	 * <code>
	 * &lt;fitnesses&gt;<BR/>
	 *     &lt;fitnesse&gt;<BR/>
	 *         &lt;pageName&gt;This is the only required parameter, the name of the FitNesse page&lt;/pageName&gt;<BR/>
	 *         &lt;hostName&gt;default is <i>locahost</i>&lt;/hostName&gt;<BR/>
	 *         &lt;port&gt;: default is <i>80</i>;&lt;/port&gt;<BR/>
	 *         &lt;serverId&gt;serverId defined in your settings.xml, this allows to use credentials (basic athentification) for sending files&lt;/serverId&gt;<BR/>
	 *         &lt;type&gt;Override the default type of the page (Suite or Test).;&lt;/type&gt;<BR/>
	 *         &lt;/fitnesse&gt;<BR/>
	 *     ... <BR/>
	 * &lt;/fitnesses&gt;:<BR/>
	 * </code>
	 * 
	 * @parameter
	 */
	protected String[] includes;

	
	/**
	 * excludes
	 * 
	 * @parameter
	 */
	protected String[] excludes;

	/**
	 * The Jar archiver.
	 * 
	 * @parameter expression="${component.org.codehaus.plexus.archiver.Archiver#jar}"
	 * @required
	 */
	protected JarArchiver jarArchiver;

	/**
	 * Local maven repository.
	 * 
	 * @parameter expression="${localRepository}"
	 * @required
	 * @readonly
	 */
	protected ArtifactRepository localRepository;

	/**
	 * @parameter expression="${project.remoteArtifactRepositories}"
	 * @readonly
	 */
	protected List remoteRepositories;

	/**
	 * @parameter expression="${component.org.apache.maven.artifact.factory.ArtifactFactory}"
	 * @required
	 * @readonly
	 */
	protected ArtifactFactory artifactFactory;

	/**
	 * @component
	 * @readonly
	 */
	protected ArtifactMetadataSource metadataSource;

	/**
	 * List of the servers.
	 * 
	 * @parameter expression="${settings.servers}"
	 * @required
	 * @readonly
	 */
	protected List servers = new ArrayList();

	/**
	 * The set of dependencies required by the project
	 * 
	 * @parameter default-value="${project.dependencies}"
	 * @required
	 * @readonly
	 */
	protected List dependencies;

	/**
	 * Artifact resolver used to find clovered artifacts (artifacts with a
	 * clover classifier).
	 * 
	 * @component role="org.apache.maven.artifact.resolver.ArtifactResolver"
	 * @required
	 * @readonly
	 */
	protected ArtifactResolver artifactResolver;

	public void setDebug(boolean debug) {
		String strDebug = System.getProperty("ntaf.debug");

		if (strDebug != null) {
			this.debug = Boolean.valueOf(strDebug).booleanValue();
		} else {
			this.debug = debug;
		}
	}

	public abstract void execute() throws MojoExecutionException, MojoFailureException;

	protected Server getServer(String serverId) {
		for (Iterator iterator = servers.iterator(); iterator.hasNext(); ) {
			Server server = (Server) iterator.next();

			if (server.getId().equals(serverId)) {
				return server;
			}
		}

		return null;
	}

	protected Set getDependencies() throws MojoExecutionException {
		Set dependencyArtifacts;

		try {
			dependencyArtifacts = MavenMetadataSource.createArtifacts(artifactFactory, dependencies, null, null, null);
		} catch (InvalidDependencyVersionException e) {
			throw new MojoExecutionException("Invalid dependency", e);
		}

		dependencyArtifacts.add(project.getArtifact());
		List listeners = Collections.EMPTY_LIST;

		ArtifactResolutionResult result;

		try {
			result = artifactResolver.resolveTransitively(dependencyArtifacts, project.getArtifact(), Collections.EMPTY_MAP,
					localRepository, remoteRepositories, metadataSource, null, listeners);
		} catch (ArtifactResolutionException e) {
			throw new MojoExecutionException("Unable to resolve Artifact.", e);
		} catch (ArtifactNotFoundException e) {
			throw new MojoExecutionException("Unable to resolve Artifact.", e);
		}

		return result.getArtifacts();
	}
}
